//
//  tdl/meta/type_traits.h
//  Created by tommywang on 12-7-21.
//

#ifndef tdl_meta_typetraits_h
#define tdl_meta_typetraits_h

#include "meta/btypes.h"
#include "meta/type_list.h"
#include "utils/time.h"
using namespace tdl;

namespace tdl {
///////////////
template <typename T> struct type_traits
{
private:
	template <typename U> struct pointer_helper
	{
		enum { is_pointer = false };
		typedef U pointee_type;
	};
	template <typename U> struct pointer_helper<U*>
	{
		enum { is_pointer = true };
		typedef U pointee_type;
	};
	template <typename U> struct pointer_helper<U[]>
	{
		enum { is_pointer = true };
		typedef U pointee_type;
	};
	////////////////
	template <typename U> struct ref_helper
	{
		enum { is_reference = false };
		typedef U reference_type;
	};
	template <typename U> struct ref_helper<U&>
	{
		enum { is_reference = true };
		typedef U reference_type;
	};
	////////////////
	template <typename U> struct const_helper
	{
		enum { is_const = false };
		typedef U deconst_type;
	};
	template <typename U> struct const_helper<const U>
	{
		enum { is_const = true };
		typedef U deconst_type;
	};
	template <typename U> struct const_helper<const U*>
	{
		enum { is_const = true };
		typedef U* deconst_type;
	};
	template <typename U> struct const_helper<const U&>
	{
		enum { is_const = true };
		typedef U& deconst_type;
	};
	////////////////
	template <typename U> struct org_helper
	{
		typedef U org_type;
	};
	template <typename U> struct org_helper<const U*>
	{
		typedef U org_type;
	};
	template <typename U> struct org_helper<const U&>
	{
		typedef U org_type;
	};
	////////////////
	template <typename F> struct func_helper
	{
		enum { is_func = false };
		typedef F ret_type;
	};
	template <typename TR> struct func_helper<TR (*)()>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR> struct func_helper<TR (*)(...)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1> struct func_helper<TR (*)(P1)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2> struct func_helper<TR (*)(P1, P2)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3> struct func_helper<TR (*)(P1, P2, P3)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4>
	struct func_helper<TR (*)(P1, P2, P3, P4)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5>
	struct func_helper<TR (*)(P1, P2, P3, P4, P5)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
	struct func_helper<TR (*)(P1, P2, P3, P4, P5, P6)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
	struct func_helper<TR (*)(P1, P2, P3, P4, P5, P6, P7)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7,
			typename P8> struct func_helper<TR (*)(P1, P2, P3, P4, P5, P6, P7, P8)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7,
			typename P8, typename P9> struct func_helper<TR (*)(P1, P2, P3, P4, P5, P6, P7, P8, P9)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	template <typename TR, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7,
			typename P8, typename P9, typename P10> struct func_helper<TR (*)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>
	{
		enum { is_func = true };
		typedef TR ret_type;
	};
	////////////////
	template <typename MF> struct memfun_helper
	{
		enum { is_memfun = false };
		typedef MF ret_type;
		typedef MF obj_type;
	};
	template <typename TR, typename Tclass> struct memfun_helper<TR (Tclass::*)()>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass> struct memfun_helper<TR (Tclass::*)(...)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1> struct memfun_helper<TR (Tclass::*)(P1)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2> struct memfun_helper<TR (Tclass::*)(P1, P2)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3> struct memfun_helper<TR (Tclass::*)(P1, P2, P3)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4>
	struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5>
	struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
	struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5, P6)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6,
			typename P7> struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5, P6, P7)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6,
			typename P7, typename P8> struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5, P6, P7, P8)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6,
			typename P7, typename P8, typename P9> struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5, P6, P7, P8, P9)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};
	template <typename TR, typename Tclass, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7,
			typename P8, typename P9, typename P10> struct memfun_helper<TR (Tclass::*)(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>
	{
		enum { is_memfun = true };
		typedef TR ret_type;
		typedef Tclass obj_type;
	};

public:
	enum { is_pointer = pointer_helper<T>::is_pointer };
	typedef typename pointer_helper<T>::pointee_type pointee_type;

	enum { is_reference = ref_helper<T>::is_reference };
	typedef typename ref_helper<T>::reference_type reference_type;

	enum { is_const = const_helper<T>::is_const };
	typedef typename const_helper<T>::deconst_type deconst_type;

	typedef typename org_helper<T>::org_type org_type;
	
	enum { is_fun = func_helper<T>::is_func };
	typedef typename func_helper<T>::ret_type ret_type;
	
	enum { is_memfun = memfun_helper<T>::is_memfun };
	typedef typename memfun_helper<T>::ret_type memfun_ret_type;
	typedef typename memfun_helper<T>::obj_type memfun_obj_type;

public:
	// basic types traits
	typedef make_type_list<char, short int, int, long long int>::type signed_ints_type;
	typedef make_type_list<int8_t, int16_t, int32_t, int64_t>::type signed_intx_t_type;
	typedef make_type_list<unsigned char, unsigned short int, unsigned int, unsigned long long int>::type unsigned_ints_type;
	typedef make_type_list<uint8_t, uint16_t, uint32_t, uint64_t>::type unsigned_intx_t_type;
	typedef make_type_list<float, double>::type float_type;
	typedef make_type_list<time_t, msec_t, usec_t>::type time_type;

	enum { is_signed_int = tlop::exists<signed_ints_type, org_type>::value || tlop::exists<signed_intx_t_type, org_type>::value };
	enum { is_unsigned_int = tlop::exists<unsigned_ints_type, org_type>::value || tlop::exists<unsigned_intx_t_type, org_type>::value };
	enum { is_stdint = is_signed_int || is_unsigned_int };
	enum { is_float = tlop::exists<float_type, T>::value };
	enum { is_time = tlop::exists<time_type, T>::value };

public:
	// function's parameter_type
	typedef typename type_selector<T, reference_type&, is_stdint || is_float || is_pointer || is_time>::type param_type;
	typedef typename type_selector<const T, const reference_type&, is_stdint || is_float || is_pointer || is_time>::type const_param_type;
};

/////////////////
}	// namespace tdl

#endif

